﻿using System;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Threading;
using System.Windows;
using System.Windows.Navigation;
using GBAExtentionLib;
using GarboDev;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Rectangle = Microsoft.Xna.Framework.Rectangle;

namespace GBAEmulator_XNA
{
    public partial class GamePage : PhoneApplicationPage
    {
        ContentManager _contentManager;
        readonly GameTimer _timer;
        SpriteBatch _spriteBatch;
        private GbaManager _gbaManager;
        private readonly Rectangle _monitorRectangle = new Rectangle(220, 0, 360, 240);
        public GamePage()
        {
            InitializeComponent();

            // 从应用程序中获取内容管理器
            _contentManager = (Application.Current as App).Content;

            // 为此页面创建计时器
            _timer = new GameTimer { UpdateInterval = TimeSpan.FromTicks(333333) };
            _timer.Update += OnUpdate;
            _timer.Draw += OnDraw; 
            Loaded += (sender, e) =>
            {
                InitialGBAManager();
                LoadBios();
                LoadRom();
            };
        }

        void InitialGBAManager()
        {
            _gbaManager = new GbaManager();
            SetRender();

            new Thread(() =>
            {
                while (true)
                {
                    CheckKeyHit();
                    Thread.Sleep(50);
                }
            }).Start();
        }

        private void SetRender()
        {
            bool wasHalted = _gbaManager.Halted;
            _gbaManager.Halt();
            _gbaManager.VideoManager.Presenter = Render2D;

            var renderer = new XNARenderer();
            renderer.Initialize(null);

            _gbaManager.VideoManager.Renderer = renderer;

            if (!wasHalted)
            {
                _gbaManager.Resume();
            }
        }

        void LoadBios()
        {
            try
            {
                using (var stream = Application.GetResourceStream(new Uri("/GBAEmulator_XNA;component/bios.bin", UriKind.Relative)).Stream)//FileStream(this.biosFilename, FileMode.Open))
                {
                    var rom = new byte[(int)stream.Length];
                    stream.Read(rom, 0, (int)stream.Length);

                    _gbaManager.LoadBios(rom);
                }
                _gbaManager.Resume();
            }
            catch (Exception exception)
            {
                MessageBox.Show("Unable to load bios file, disabling bios (irq's will not work)\n" + exception.Message);
            }
        }

        void LoadRom()
        {
            using (var stream = new IsolatedStorageFileStream("/Games/口袋吧绿宝石386中文版.gba", FileMode.Open, FileAccess.Read, IsolatedStorageFile.GetUserStoreForApplication()))
            {
                LoadRom(stream);
            }
        }

        void LoadRom(Stream stream)
        {
            int romSize = 1;
            while (romSize < stream.Length)
            {
                romSize <<= 1;
            }

            var rom = new byte[romSize];
            stream.Read(rom, 0, (int)stream.Length);

            _gbaManager.LoadRom(rom);

            _gbaManager.Resume();
        }

        private void CheckKeyHit()
        {
            _gbaManager.KeyState = GameButtonKeyService.GetInstance().GetKeyStates();
        }

        private const string SavePath = "GameSave";
        private string _gameName = string.Empty;

        private void LoadGameClick(object sender, RoutedEventArgs e)
        {
            //_gbaManager.Halt();
            //GBAWatcherService.Start(GBAFileChooser, fileSelectorEvent =>
            //{
            //    if (fileSelectorEvent == null)
            //    {
            //        _gbaManager.Resume();
            //        return;
            //    }
            //    var stream =
            //        new IsolatedStorageFileStream(
            //            fileSelectorEvent.SelectedFile.FullName, FileMode.Open,
            //            IsolatedStorageFile.GetUserStoreForApplication());
            //    LoadRom(stream);
            //    _gameName = Regex.Replace(fileSelectorEvent.SelectedFile.Name, ".gba$", "");
            //});
        }

        //private MemorySave _save;

        private void SaveClick(object sender, RoutedEventArgs e)
        {
            //_save = gbaManager.Save();
            if (string.IsNullOrEmpty(_gameName)) return;
            _gbaManager.Halt();
            using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!storage.DirectoryExists(SavePath))
                    storage.CreateDirectory(SavePath);
                if (!storage.DirectoryExists(string.Format("{0}\\{1}", SavePath, _gameName)))
                    storage.CreateDirectory(string.Format("{0}\\{1}", SavePath, _gameName));
                if (storage.FileExists(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav")))
                    storage.DeleteFile(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"));
                using (var stream = storage.OpenFile(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"), FileMode.OpenOrCreate))
                {
                    var save = _gbaManager.Save();
                    GameSaveHandler.Save(stream, save);
                    stream.Flush();
                    stream.Close();
                    stream.Dispose();
                }
            }

            _gbaManager.Resume();
        }

        private void LoadClick(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(_gameName)) return;
            using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!storage.FileExists(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"))) return;
                _gbaManager.Halt();
                using (
                    var stream =
                        IsolatedStorageFile.GetUserStoreForApplication().OpenFile(
                            string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"), FileMode.Open)
                    )
                {
                    var save = GameSaveHandler.Load(stream);
                    stream.Flush();
                    stream.Close();
                    _gbaManager.LoadSave(save);
                    stream.Dispose();
                }
            }
            //gbaManager.LoadSave(_save);
            _gbaManager.Resume();
        }

        private uint[] Data { get; set; }

        private long RenderCount = 0;
        private long DrawCount = 0;

        private void Render2D(object data)
        {
            Data = data as uint[];
            Debug.WriteLine(string.Format("Rendered:{0}",++RenderCount));
        }
        
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // 设置图形设备的共享模式以启用 XNA 呈现
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            // 创建可以用来绘制纹理的新 SpriteBatch。
            _spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

            // TODO: 使用 this.content 在此处加载游戏内容

            // 启动计时器
            _timer.Start();

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 停止计时器
            _timer.Stop();

            // 设置图形设备的共享模式以禁用 XNA 呈现
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        /// 允许页面运行逻辑，如更新环境、
        /// 检查冲突、收集输入和播放音频。
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            // TODO: 在此处添加更新逻辑
        }

        /// <summary>
        /// 允许页面绘制自身。
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            // TODO: 在此处添加绘制代码
            try
            {
                Debug.WriteLine(string.Format("Drawn:{0}", ++DrawCount));
                SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);
                //TODO: 在此处添加绘图代码
                _spriteBatch.Begin();
                var t2D = new Texture2D(SharedGraphicsDeviceManager.Current.GraphicsDevice, GBA.Constant.Width, GBA.Constant.Height);
                t2D.SetData(Data);
                _spriteBatch.Draw(t2D, _monitorRectangle, Color.White);
                _spriteBatch.End();
                t2D.Dispose();
            }
            catch (Exception)
            {
                _spriteBatch.End();
            }
        }
    }
}